package gang.org.springframework.framework.beanpostprocessor;

import gang.org.springframework.framework.bean.GangRootBeanDefinition;
import gang.org.springframework.framework.core.annotation.GangAnnotationUtils;
import gang.org.springframework.framework.factory.annotation.GangInjectionMetadata;
import gang.org.springframework.framework.factory.annotation.lookup;
import gang.org.springframework.framework.metadata.GangMergedAnnotation;
import gang.org.springframework.framework.util.GangClassUtils;
import gang.org.springframework.framework.util.GangReflectionUtils;
import gang.org.springframework.framework.util.GangStringUtils;

import java.lang.reflect.Constructor;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author gang.chen
 * @since 2021/8/13 13:24
 */
public class GangAutowiredAnnotationBeanPostProcessor implements GangSmartInstantiationAwareBeanPostProcessor, GangMergedBeanDefinitionPostProcessor
{

    public final Set<String> lookupMethodsChecked = Collections.newSetFromMap(new ConcurrentHashMap<>(256));
    
    public final Map<Class<?>, Constructor<?>[]> candidateConstrutorsCaches= new ConcurrentHashMap<>(256);

    public final Map<String, GangInjectionMetadata> injectionMetadataCaches = new ConcurrentHashMap<>(256);

    @Override
    public void postProcessMergedBeanDefinition(GangRootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        GangInjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
    }


    @Override
    public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) {
        /*
         * let's check for lookup methods here
         * #############################################################
         * #场景一 业务意义：
         * ##############################################################
         * */
        if (!this.lookupMethodsChecked.contains(beanName)) {

            if (GangAnnotationUtils.isCandidateClass(beanClass, lookup.class)) {
                try {
                    Class<?> targetClass = beanClass;
                    do{
                        GangReflectionUtils.doWithLocalMethod(targetClass, method -> {
                            //TODO
                        });
                        targetClass = targetClass.getSuperclass();
                    }
                    while (targetClass != null && targetClass!=Object.class);

                }catch (Exception e){
                    e.printStackTrace();
                }
            }
            this.lookupMethodsChecked.add(beanName);
        }
        /*
         * let's check for lookup methods here
         * #############################################################
         * #场景二 业务意义：
         * ##############################################################
         * */
        Constructor<?>[] candidateConstructors = this.candidateConstrutorsCaches.get(beanClass);
        if (candidateConstructors == null && beanClass != null) {
            synchronized (this.candidateConstrutorsCaches){
                candidateConstructors= this.candidateConstrutorsCaches.get(beanClass);
                if (candidateConstructors == null) {
                    Constructor<?>[] rawCandidates = new Constructor[0];
                    try {
                        rawCandidates = beanClass.getDeclaredConstructors();
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    
                    List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
                    Constructor<?> requiredConstructor = null;
                    Constructor<?> defaultConstructor = null;
                    Constructor<?> primaryConstructor = null;
                    int nonSyntheticConsructor = 0;
                    for (Constructor<?> candidate : rawCandidates) {
                        if (!candidate.isSynthetic()) {
                            nonSyntheticConsructor++;
                        }
                        GangMergedAnnotation<?> ann = null;
                        if (ann == null) {
                            Class<?> userClass = GangClassUtils.getUserClass(beanClass);
                            if (userClass != beanClass) {
                                //TODO
                            }
                        }

                        if (ann != null) {
                            //TODO
                        }
                        else if(candidate.getParameterCount() == 0){
                            //TODO
                        }
                    }
                    if (!candidates.isEmpty()) {
                        //TODO
                    }
                    else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() >0){
                        candidateConstructors = new Constructor[]{rawCandidates[0]};
                    }
                    //else if TODO

                    //else if TODO
                    else {
                        candidateConstructors = new Constructor<?>[0];
                    }
                    this.candidateConstrutorsCaches.put(beanClass, candidateConstructors);
                }
            }
        }
        return candidateConstructors.length > 0 ? candidateConstructors:null;
    }

    public GangInjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, Object pvs){
        String cacheKey = GangStringUtils.hasLength(beanName) ? beanName : clazz.getName();

        GangInjectionMetadata metadata = this.injectionMetadataCaches.get(cacheKey);

        return metadata;
    }
}
